#ifndef __MEMORY__H__
#define __MEMORY__H__

#include <utility>
#include "detail/ref.h"

namespace mnx {
template<class _T>
class cow_ptr;

template<class T>
struct default_delete {
    void operator ( )(T* ptr) {
        if (ptr)
            delete ptr;
    }
};

template<class T>
struct default_delete <T[]> {
    void operator ( )(T* ptr) {
        if (ptr)
            delete[] ptr;
    }
}

template<class T>
class shared_ptr {
 public:
    typedef T element_type;

 private:
    template<class Type>
    using ref_t = detail::ref_t <Type>;

 public:
    explicit shared_ptr(T *p = nullptr) : ref_(new ref<T>(p)) {}
    template<class D>
    shared_ptr(T *p, D del) : ref_(new ref_t<T>(p, del)) {}
    shared_ptr(const shared_ptr& sp) {
        copy_ref(sp.ref_);
    }
    shared_ptr& operator = (const shared_ptr& sp) {
        if (this != &sp) {
            decrease_ref();
            copy_ref(sp.ref_);
        }
        return *this;
    }
    ~shared_ptr() {
        decrease_ref();
    }
    const element_type& operator *() const { return *(get()); }

 private:
    void decrease_ref() {
        if (ref_->get_data()) {
            --(*ref_);
            if (use_count() == 0)
                delete ref_;
        }
    }
    void copy_ref(ref_t<T> *r) {
        ref_ = r;
        ++(*ref_);
    }

 private:
    ref_t<T> *ref_;
};

}  // end namespace mnx

#endif  // !__MEMORY__H__
